#ifndef PLAYSTATE_H
#define PLAYSTATE_H

#include <stdlib.h>
#include <vector>

#include "GameState.h"
#include "CameraControl.h"
#include "Player.h"
#include "GameSession.h"

class MenuInGame;

typedef std::vector<Player*> PlayerVector;

/*
 * Base class that handles playing a level
 */
class PlayState : public GameState
{
    friend class QuickPlayManager;
    friend class StoryModeManager;

public:
    static PlayState *play_state;
    static FILE *out_file;
    
	PlayState(void);
   ~PlayState(void);
	
	void getStatePointers();
	

    // override to handle keyboard key pressed events in different ways in each
    // different play state
	virtual bool keyPressed(const OIS::KeyEvent &)  = 0;
	bool keyReleased(const OIS::KeyEvent &);
	bool mouseMoved(const OIS::MouseEvent &);
	bool mousePressed(const OIS::MouseEvent &, OIS::MouseButtonID);
	bool mouseReleased(const OIS::MouseEvent &, OIS::MouseButtonID);
	
	bool frameStarted(const Ogre::FrameEvent &evt);
    bool frameEnded(const Ogre::FrameEvent &evt);
    bool pause(void);
    void resume();
	
	GameSession *getGameSession();
	Ogre::Real getPlayDuration();
	void fallOut(OgreNewt::Body *me);
	void addTime(Ogre::Real t);
	
	void playSound(SourceIndex i);
	void setStopPlaying(bool sp) {stop_playing = sp;}
	
	void updateLifeOverlay();
	void updateScoreOverlay();
	void showSizeOverlay(int id);
	void hideSizeOverlay(int id);
	void showInvertOverlay(int id);
	void hideInvertOverlay(int id);
	void showSpeedOverlay(int id);
	void hideSpeedOverlay(int id);
	void showSensitivityOverlay(int id);
	void hideSensitivityOverlay(int id);
	
    bool isPodControlOn();
    void simulateAcceleration(Ogre::Vector3 normal, Ogre::Vector3 ball_direction, float ball_speed);
    void addDownwardMovement();
    void homePod();
    void ballCollision(float volume);

    void setCamera(CameraControl *c);
    static void addPlayer(Player *p, bool main = false);
    static void removeAllPlayers();
    static GameSession *getMainPlayersSession() { return main_player_session; }
	GameResources *getResources() { return resources; }
protected:
    // override these to provide for anything extra that is needed as the level
    // is starting or stopping being played
    virtual void enterExtras() {}
    virtual void startPlaying() = 0;
    virtual void stopPlaying() = 0;
    // override to assign input devices to all the players
    virtual void initialisePlayers() = 0;
    virtual bool ogreNewtNeedsUpdate() = 0;
    virtual float getOgreNewtUpdateTime() = 0;
    virtual void setStopPlaying() = 0;
    virtual void playerFallout() {}
    virtual void initialiseHUD();
    virtual void updateHUD(Ogre::Real timeSinceLastFrame);
    virtual void initialiseCountdownOverlay();
    virtual void updateCountdownOverlay();
    virtual void initialiseExtraOverlays() {}
    virtual void updateExtraOverlays() {}
    virtual float getTimeUntilUserCanControl() { return 3.0; }

    static PlayerVector players;
    static Player *main_player, *ghost;
    static GameSession *main_player_session;
	float timer_goal;
	CameraControl *camera;
    Ogre::SceneNode *skybox_node;
    Ogre::Real time_until_user_can_control;
    bool stop_playing;
    bool stats_visible;
    bool overlays_enabled;
    Ogre::OverlayElement *countdown;
    Ogre::Overlay *countdown_overlay, *hud_overlay, *stats_overlay, *pickup_overlay;
    std::string getCountdownText();
    void enter(void);
	void exit(void);
	int ogre_frame_count;
    Ogre::Real ogre_time, ogre_newt_time, simulated_time;
    void initialisePickupOverlays();
    int num_pickups_active;
    struct active_pickup {
        int id;
        Ogre::OverlayElement* overlay;
    };
    std::vector<struct active_pickup> active_pickups;
    // Keep a in game menu pointer for pause menu and also options
    MenuInGame *menu;
    float play_speed;
    bool in_replay;
};

#endif
